package com.canaan.business.service.bill.impl;

import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.canaan.business.common.enums.basic.YNEnum;
import com.canaan.business.common.enums.inOutStock.OutOrderStatusEnum;
import com.canaan.business.common.enums.inOutStock.OutStockOrderTypeEnum;
import com.canaan.business.common.enums.invoice.MaterialPreparationStatusEnum;
import com.canaan.business.domain.basic.WmsProduct;
import com.canaan.business.domain.bill.MaterialPreparationDetail;
import com.canaan.business.domain.inOutStock.PickerTaskOrder;
import com.canaan.business.domain.inOutStock.WmsOutStockDetailOrder;
import com.canaan.business.domain.inOutStock.WmsOutStockOrder;
import com.canaan.business.domain.vo.DistributeMaterialPreparationVo;
import com.canaan.business.domain.vo.InventoryOverviewVo;
import com.canaan.business.domain.vo.MaterialPreparationExportVo;
import com.canaan.business.service.basic.IWmsProductService;
import com.canaan.business.service.bill.IMaterialPreparationDetailService;
import com.canaan.business.service.inOutStock.IPickerTaskOrderService;
import com.canaan.business.service.inOutStock.IWmsOutStockDetailOrderService;
import com.canaan.business.service.inOutStock.IWmsOutStockOrderService;
import com.canaan.business.service.inOutStock.IWmsStockOccupyService;
import com.canaan.business.service.storehouse.IWmsStorehouseStockService;
import com.canaan.common.constant.PrefixConstants;
import com.canaan.common.exception.ServiceException;
import com.canaan.common.utils.DateUtils;
import com.canaan.common.utils.SecurityUtils;
import com.canaan.common.utils.TableNoUtil;
import com.canaan.common.utils.StringUtils;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import com.canaan.business.mapper.bill.MaterialPreparationMapper;
import com.canaan.business.domain.bill.MaterialPreparation;
import com.canaan.business.service.bill.IMaterialPreparationService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import oshi.driver.mac.net.NetStat;

/**
 * 生产备料申请Service业务层处理
 *
 * @author huangxs
 * @date 2023-09-13
 */
@Service
public class MaterialPreparationServiceImpl implements IMaterialPreparationService {
    @Resource
    private MaterialPreparationMapper materialPreparationMapper;
    @Resource
    private IMaterialPreparationDetailService materialPreparationDetailService;
    @Resource
    private IWmsStorehouseStockService storehouseStockService;
    @Resource
    private IWmsOutStockOrderService outStockOrderService;
    @Resource
    private IWmsOutStockDetailOrderService outStockDetailOrderService;
    @Resource
    private IWmsProductService productService;
    @Resource
    private IPickerTaskOrderService pickerTaskOrderService;
    @Resource
    private IWmsStockOccupyService wmsStockOccupyService;

    /**
     * 查询生产备料申请
     *
     * @param id 生产备料申请主键
     * @return 生产备料申请
     */
    @Override
    public MaterialPreparation selectMaterialPreparationById(Long id) {
        return materialPreparationMapper.selectMaterialPreparationById(id);
    }

    /**
     * 查询生产备料申请列表
     *
     * @param materialPreparation 生产备料申请
     * @return 生产备料申请
     */
    @Override
    public List<MaterialPreparation> selectMaterialPreparationList(MaterialPreparation materialPreparation) {
        return materialPreparationMapper.selectMaterialPreparationList(materialPreparation);
    }

    /**
     * 新增生产备料申请
     *
     * @param materialPreparation 生产备料申请
     * @return 结果
     */
    @Override
    public int insertMaterialPreparation(MaterialPreparation materialPreparation) {
        if(StringUtils.isBlank(materialPreparation.getNo())){
            materialPreparation.setNo(PrefixConstants.MP_SQ+TableNoUtil.getNo(MaterialPreparation.class));
        }
        materialPreparation.setOrderStatus(MaterialPreparationStatusEnum.NEW.getCode());
        materialPreparation.setCreateBy(SecurityUtils.getUsername());
        materialPreparation.setCreateTime(DateUtils.getNowDate());
        return materialPreparationMapper.insertMaterialPreparation(materialPreparation);
    }

    /**
     * 批量新增生产备料申请
     *
     * @param materialPreparationList 生产备料申请列表
     * @return 结果
     */
    @Override
    public int batchInsertMaterialPreparation(List<MaterialPreparation> materialPreparationList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (MaterialPreparation materialPreparation : materialPreparationList){
            if(StringUtils.isBlank(materialPreparation.getNo())){
                materialPreparation.setNo(TableNoUtil.getNo(MaterialPreparation.class));
            }
            materialPreparation.setCreateBy(username);
            materialPreparation.setCreateTime(currerTime);
        }
        int insertNum = 0;
        for (int i=0; i<materialPreparationList.size();) {
            int endIndex = i+500;
            if (endIndex > materialPreparationList.size()) {
                endIndex = materialPreparationList.size();
            }
            insertNum = insertNum + materialPreparationMapper.batchInsertMaterialPreparation(materialPreparationList.subList(i, endIndex));
            i = endIndex;
        }
        return insertNum;
    }

    /**
     * 修改生产备料申请
     *
     * @param materialPreparation 生产备料申请
     * @return 结果
     */
    @Override
    public int updateMaterialPreparation(MaterialPreparation materialPreparation) {
        materialPreparation.setUpdateBy(SecurityUtils.getUsername());
        materialPreparation.setUpdateTime(DateUtils.getNowDate());
        return materialPreparationMapper.updateMaterialPreparation(materialPreparation);
    }

    /**
     * 批量修改生产备料申请
     *
     * @param materialPreparationList 生产备料申请列表
     * @return 结果
     */
    @Override
    public int batchUpdateMaterialPreparation(List<MaterialPreparation> materialPreparationList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (MaterialPreparation materialPreparation : materialPreparationList){
            materialPreparation.setUpdateBy(username);
            materialPreparation.setUpdateTime(currerTime);
        }
        int updateNum = 0;
        for (int i=0; i<materialPreparationList.size();) {
            int endIndex = i+500;
            if (endIndex > materialPreparationList.size()) {
                endIndex = materialPreparationList.size();
            }
            updateNum = updateNum + materialPreparationMapper.batchUpdateMaterialPreparation(materialPreparationList.subList(i, endIndex));
            i = endIndex;
        }
        return updateNum;
    }

    /**
     * 批量删除生产备料申请
     *
     * @param ids 需要删除的生产备料申请主键集合
     * @return 结果
     */
    @Override
    public int deleteMaterialPreparationByIds(Long[] ids) {
        return materialPreparationMapper.deleteMaterialPreparationByIds(ids);
    }

    /**
     * 删除生产备料申请信息
     *
     * @param id 生产备料申请主键
     * @return 结果
     */
    @Override
    public int deleteMaterialPreparationById(Long id) {
        return materialPreparationMapper.deleteMaterialPreparationById(id);
    }

    /**
     * 查询生产备料申请
     *
     * @param no 编号
     * @return 生产备料申请
     */
    @Override
    public MaterialPreparation selectMaterialPreparationByNo(String no) {
        return materialPreparationMapper.selectMaterialPreparationByNo(no);
    }

    /**
     * 批量删除生产备料申请
     *
     * @param nos 需要删除的编号集合
     * @return 结果
     */
    @Override
    public int deleteMaterialPreparationByNos(String[] nos) {
        return materialPreparationMapper.deleteMaterialPreparationByNos(nos);
    }

    /**
     * 删除生产备料申请信息
     *
     * @param no 编号
     * @return 结果
     */
    @Override
    public int deleteMaterialPreparationByNo(String no) {
        return materialPreparationMapper.deleteMaterialPreparationByNo(no);
    }

    /**
     * 确认
     * @param id
     * @return
     */
    @Override
    public int confirm(long id) {
        MaterialPreparation mp = this.materialPreparationMapper.selectMaterialPreparationById(id);
        if (mp!=null){
            if(mp.getOrderStatus() != MaterialPreparationStatusEnum.NEW.getCode()){
                throw new ServiceException("新建状态才能确认单据");
            }
           List<MaterialPreparationDetail> details = this.materialPreparationDetailService.selectByOrderNo(mp.getNo());
           if (CollectionUtils.isEmpty(details)){
               throw new ServiceException("备料清单不能为空");
           }
           mp.setOrderStatus(MaterialPreparationStatusEnum.CONFIRMED.getCode());
           this.materialPreparationMapper.updateMaterialPreparation(mp);
        }else{
            throw new ServiceException("单据不存在");
        }
        return 1;
    }

    @Override
    public DistributeMaterialPreparationVo getDistributeInfo(Long id) {
        DistributeMaterialPreparationVo vo = new DistributeMaterialPreparationVo();
        MaterialPreparation mp = this.materialPreparationMapper.selectMaterialPreparationById(id);
        if (mp!=null){
            if(mp.getOrderStatus() == MaterialPreparationStatusEnum.CONFIRMED.getCode()||mp.getOrderStatus()==MaterialPreparationStatusEnum.IN_HAND.getCode() ){
                BeanUtil.copyProperties(mp,vo);
                vo.setIssuedQty(0l);
                vo.setStockQty(0l);
                vo.setAssignedQty(0L);
                //获取已下发数量
                List<WmsOutStockOrder> outStockOrderList = outStockOrderService.selectListOrderByRelOrderNo(mp.getNo(), OutStockOrderTypeEnum.MP.getCode());
                if (!CollectionUtils.isEmpty(outStockOrderList)){
                    Long num = outStockOrderList.stream().collect(Collectors.summingLong(WmsOutStockOrder::getDistributeQty));
                    vo.setIssuedQty(num);
                }
                vo.setNotSentQty(vo.getWorkOrderQty()-vo.getIssuedQty());
                //获取备料清单
                List<MaterialPreparationDetail> details = this.materialPreparationDetailService.selectByOrderNo(mp.getNo());
                if (CollectionUtils.isEmpty(details)){
                    throw new ServiceException("备料清单不能为空");
                }
                Long stockQty = this.getStockQty(details,mp);
                vo.setStockQty(stockQty);
                if (vo.getNotSentQty()>0){
                    //获取可下发数量
                    if (vo.getNotSentQty()<=vo.getStockQty()){
                        vo.setAssignedQty(vo.getNotSentQty());
                    }else{
                        vo.setAssignedQty(vo.getStockQty());
                    }
                }
            }else{
                throw new ServiceException("只有已确认或进行中才可以下发");
            }
        }else{
            throw new ServiceException("单据不存在");
        }
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int confirmDistribute(DistributeMaterialPreparationVo vo) {
        MaterialPreparation mp = this.materialPreparationMapper.selectMaterialPreparationById(vo.getId());
        if (mp!=null){
            //获取备料清单
            List<MaterialPreparationDetail> details = this.materialPreparationDetailService.selectByOrderNo(mp.getNo());
            if (CollectionUtils.isEmpty(details)){
                throw new ServiceException("备料清单不能为空");
            }
            if (StringUtils.isEmpty(vo.getPicker())){
                throw new ServiceException("拣货人员不能为空");
            }
            Long stockQty = this.getStockQty(details,mp);
            vo.setStockQty(stockQty);
            if (vo.getNotSentQty()>0){
                //获取可下发数量
                if (vo.getNotSentQty()<=vo.getStockQty()){
                    vo.setAssignedQty(vo.getNotSentQty());
                }else{
                    vo.setAssignedQty(vo.getStockQty());
                }
            }
            if (vo.getAssignedQty()>0){
                 //生成备料拣货单
                WmsOutStockOrder outStockOrder = new WmsOutStockOrder();
                outStockOrder.setRelOrderNo(mp.getNo());
                outStockOrder.setOrderType(OutStockOrderTypeEnum.MP.getCode());
                outStockOrder.setWorkOrderNo(mp.getWorkOrderNo());
                outStockOrder.setDistributeQty (vo.getAssignedQty());
                outStockOrder.setPicker(vo.getPicker());
                outStockOrderService.insertWmsOutStockOrder(outStockOrder);
                //生成备料拣货单明细
                List<WmsOutStockDetailOrder> detailOrderList = Lists.newArrayList();
                for (MaterialPreparationDetail detail:details){
                    WmsProduct product = productService.selectWmsProductByProductNo(detail.getProductNo());
                    if (product!=null){
                        WmsOutStockDetailOrder detailOrder = new WmsOutStockDetailOrder();
                        detailOrder.setOrderNo(outStockOrder.getNo());
                        if (StringUtils.isNotEmpty(vo.getPicker())){
                            detailOrder.setOrderDetailStatus(OutOrderStatusEnum.PICKING.getCode());
                        }else{
                            detailOrder.setOrderDetailStatus(OutOrderStatusEnum.NEW.getCode());
                        }
                        detailOrder.setProductNo(detail.getProductNo());
                        detailOrder.setPickingQty(0L);
                        detailOrder.setProductName(detail.getProductName());
                        detailOrder.setUnit(product.getCompany());
                        detailOrder.setOrderQty(detail.getDosage()*vo.getAssignedQty());
                        detailOrderList.add(detailOrder);
                    }else{
                        throw new ServiceException("物料不存在："+product.getProductNo());
                    }
                }
                if (!CollectionUtils.isEmpty(detailOrderList)){
                    this.outStockDetailOrderService.batchInsertOutStockDetailOrder(detailOrderList);
                }
                if (StringUtils.isNotEmpty(vo.getPicker())){
                    List<PickerTaskOrder> pickerTaskOrderList = Lists.newArrayList();
                    outStockOrder.setOrderStatus(OutOrderStatusEnum.PICKING.getCode());
                    outStockOrderService.updateWmsOutStockOrder(outStockOrder);
                    //获取插入后的明细
                    List<WmsOutStockDetailOrder> outStockDetailOrderList = outStockDetailOrderService.listByOrderNo(outStockOrder.getNo());
                    if (!CollectionUtils.isEmpty(outStockDetailOrderList)){
                        outStockDetailOrderList.stream().forEach(e->{
                            PickerTaskOrder pickerTaskOrder = new PickerTaskOrder();
                            pickerTaskOrder.setNo(TableNoUtil.getNo(PickerTaskOrder.class));
                            pickerTaskOrder.setPicker(vo.getPicker());
                            pickerTaskOrder.setStatus(OutOrderStatusEnum.WAITING_PICK.getCode());
                            pickerTaskOrder.setOutOrderId(e.getId());
                            pickerTaskOrder.setProductNo(e.getProductNo());
                            pickerTaskOrder.setDistributeQty(e.getOrderQty());
                            pickerTaskOrder.setStorehouseAreaNo(mp.getStorehouseAreaNo());
                            pickerTaskOrder.setStorehouseNo(mp.getStorehouseNo());
                            pickerTaskOrder.setRelOrderNo(mp.getNo());
                            pickerTaskOrder.setPickingQty(0L);
                            pickerTaskOrder.setOrderQty(e.getOrderQty());
                            pickerTaskOrder.setType(OutStockOrderTypeEnum.MP.getCode());
                            pickerTaskOrderList.add(pickerTaskOrder);
                            //库存占用处理
                            String taskNo = pickerTaskOrder.getNo();
                            String storehouseNo = pickerTaskOrder.getStorehouseNo();
                            String productNo = pickerTaskOrder.getProductNo();
                            Long orderQty = pickerTaskOrder.getDistributeQty();
                            wmsStockOccupyService.stockOccupy(taskNo,storehouseNo, productNo, orderQty,null,null, YNEnum.N.getCode());
                        });
                        if (!CollectionUtils.isEmpty(pickerTaskOrderList)){
                            pickerTaskOrderService.batchInsertPickerTaskOrder(pickerTaskOrderList);
                        }
                        mp.setOrderStatus(MaterialPreparationStatusEnum.IN_HAND.getCode());
                        this.materialPreparationMapper.updateMaterialPreparation(mp);
                    }
                }else{
                    throw new ServiceException("拣货员不能为空");
                }
            }else{
                throw new ServiceException("可下发数量为0，不能下发");
            }
        }
        return 1;
    }

    @Override
    public Long getMeetStockQty(Long id) {
        MaterialPreparation mp = this.materialPreparationMapper.selectMaterialPreparationById(id);
        if (mp!=null) {
            //获取备料清单
            List<MaterialPreparationDetail> details = this.materialPreparationDetailService.selectByOrderNo(mp.getNo());
            if (CollectionUtils.isEmpty(details)) {
                throw new ServiceException("备料清单不能为空");
            }
           return this.getStockQty(details,mp);
        }
        return 0L;
    }

    @Override
    public List<String> importExcel(List<MaterialPreparationExportVo> list) {
        List<String> errList = new ArrayList<>();
        Map<String, List<MaterialPreparationExportVo>> groupMap = list.stream().collect(Collectors.groupingBy(e->e.getWorkOrderNo()+":"+e.getWorkOrderQty()+":"+e.getStorehouseAreaNo()+":"+e.getStorehouseNo()));
        Set<String> groupKeys = groupMap.keySet();
        for (String groupKey : groupKeys) {
            String[] split = groupKey.split(":");
            String workNo = split[0];
            String workQty = split[1];
            String areaNo = split[2];
            String storeHouseNo  = split[3];
            List<MaterialPreparationExportVo> salesRefundBillExportVos = groupMap.get(groupKey);
            MaterialPreparation preparation = new MaterialPreparation();
            preparation.setWorkOrderNo(workNo);
            preparation.setWorkOrderQty(Long.valueOf(workQty));
            preparation.setStorehouseAreaNo(areaNo);
            preparation.setStorehouseNo(storeHouseNo);
            this.insertMaterialPreparation(preparation);
            List<MaterialPreparationDetail> details = new ArrayList<>();
            for (MaterialPreparationExportVo materialPreparationExportVo : salesRefundBillExportVos) {
                MaterialPreparationDetail materialPreparationDetail = new MaterialPreparationDetail();
                materialPreparationDetail.setOrderNo(preparation.getNo());
                materialPreparationDetail.setRequirementQty(materialPreparationExportVo.getRequirementQty());
                materialPreparationDetail.setDosage(materialPreparationExportVo.getDosage());
                materialPreparationDetail.setProductNo(materialPreparationExportVo.getProductNo());
                WmsProduct wmsProduct = productService.selectWmsProductByProductNo(materialPreparationExportVo.getProductNo());
                if (wmsProduct == null) {
                    errList.add("无效物料编码：" + wmsProduct.getProductNo());
                    continue;
                }
                materialPreparationDetail.setProductName(wmsProduct.getProductName());
                materialPreparationDetail.setCompany(wmsProduct.getCompany());
                details.add(materialPreparationDetail);
            }
            if (CollUtil.isNotEmpty(details)) {
                materialPreparationDetailService.batchInsertMaterialPreparationDetail(details);
            }
        }
        return errList;
    }

    public Long getStockQty(List<MaterialPreparationDetail> details, MaterialPreparation mp){
        //获取备料的库存
        List<String> products = details.stream().map(MaterialPreparationDetail::getProductNo).collect(Collectors.toList());
        List<InventoryOverviewVo> stockList = storehouseStockService.selectStockTotalQty(mp.getStorehouseNo(),products);
        if (CollectionUtils.isEmpty(stockList)){
            throw new ServiceException("库存没有可备料的原材料");
        }
        Map<String,Long> stockMap = new HashMap<>();
        //获取占用库存数量
        List<InventoryOverviewVo> occupyList = storehouseStockService.selectOccupyTotalQty(mp.getStorehouseNo(),products);
        //获取可用数量
        if (!CollectionUtils.isEmpty(occupyList)){
            for (InventoryOverviewVo item:stockList){
                long qty = 0L;
                for (InventoryOverviewVo item1:occupyList){
                    if (item.getProductNo().equals(item1.getProductNo())){
                        qty = item.getYjcTotalQty()-item1.getYjcOccupyTotalQty();
                    }
                }
                stockMap.put(item.getProductNo(),qty);
            }
        }else{
            for (InventoryOverviewVo item:stockList){
                stockMap.put(item.getProductNo(),item.getYjcTotalQty());
            }
        }
        List<Long> qtyList = Lists.newArrayList();
        for (MaterialPreparationDetail detail: details){
            Long stockQty = stockMap.get(detail.getProductNo());
            if(stockQty!=null){
                if (detail.getDosage().longValue()==0){
                    throw new ServiceException("单位用量不能为0");
                }
                long qty = stockQty/detail.getDosage().longValue();
                if (qty>=1){
                    qtyList.add(qty);
                }else{
                    qtyList.add(0L);
                }
            }else{
                qtyList.add(0L);
            }
        }
        long minqty = Collections.min(qtyList);
        return minqty;
    }
}
